package com.ele.server.util;

import com.ele.shared.AttachmentException;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.Arrays;
import java.util.List;

public class ImageWriter {

	private List<String> extensions = Arrays.asList("png", "jpg", "jpeg", "gif", "bmp");

	private BufferedImage image;
	private String path;
	private String extension;

	public ImageWriter(BufferedImage image, String extension, String path) throws AttachmentException {
		this.image = image;
		this.extension = extension;
		this.path = path;

		if (isTooLarge(image)) {
			throw new AttachmentException("Image is larger than 3900 x 3900.");
		}
	}

	public void write(String filename) throws AttachmentException {
		write(filename, image);
	}

	public void write(String filename, int imageSize) throws AttachmentException {
		write(filename, resize(image, imageSize));
	}

	private void write(String filename, BufferedImage image) throws AttachmentException {
		ByteArrayOutputStream bytestream = null;
		BufferedOutputStream bos = null;
		FileOutputStream fos = null;

		try {
			bytestream = new ByteArrayOutputStream();
			bos = new BufferedOutputStream(bytestream);	//initialize buffer output stream for efficiency

			writeImage(image, bos, extension);

			bytestream.flush();
			byte[] newimage = bytestream.toByteArray();	//convert the bytes in stream to byte array

			String ImageMain = path + "/" + filename + "" + extension;	//specify the file name

			fos = new FileOutputStream(ImageMain);
			fos.write(newimage);
			fos.flush();
		} catch (FileNotFoundException e) {
			throw new AttachmentException("Destination file not found", e);
		} catch (IOException e) {
			throw new AttachmentException(e);
		} finally {
			if (bytestream != null) try {
				bytestream.close();
			} catch (IOException logOrIgnore) { }
			if (bos != null) try {
				bos.close();
			} catch (IOException logOrIgnore) { }
			if (fos != null) try {
				fos.close();
			} catch (IOException logOrIgnore) { }
		}
	}

	private boolean isTooLarge(BufferedImage bufimg) {
		int img_width = bufimg.getWidth();
		int img_height = bufimg.getHeight();

		return img_width > 3900 || img_height > 3900;
	}

	private BufferedImage resize(BufferedImage bufimg, double maxImageSize) throws AttachmentException {
		double img_width = bufimg.getWidth();
		double scale = maxImageSize / img_width;
		Image sized = getScaledInstanceAWT(bufimg, scale, Image.SCALE_SMOOTH);
		return toBufferedImage(sized, BufferedImage.TYPE_INT_RGB);
	}

	private void writeImage(BufferedImage resized, BufferedOutputStream bos, String fileExtension) throws IOException {
		if (extensions.contains(fileExtension)) {
			ImageIO.write(resized, fileExtension, bos);
		}
	}

	public BufferedImage toBufferedImage(Image image, int type) throws AttachmentException {
		BufferedImage result = null;
		try {
			int w = image.getWidth(null);
			int h = image.getHeight(null);
			result = new BufferedImage(w, h, type);
			Graphics2D g = result.createGraphics();
			g.drawImage(image, 0, 0, null);
			g.dispose();
		} catch (Exception e) {
			throw new AttachmentException("Failure on image converting", e);
		}

		return result;
	}

	public Image getScaledInstanceAWT(BufferedImage source, double scale, int hint) throws AttachmentException {
		Image newimage = null;
		try {
			int w = (int) (source.getWidth() * scale);
			int h = (int) (source.getHeight() * scale);
			newimage = source.getScaledInstance(w, h, hint);
		} catch (Exception e) {
			throw new AttachmentException("Failure on image scaling", e);
		}

		return newimage;
	}
}
